/**
 * @file ipeYolov5Param.h
 * @author SDK_TEAM
 * @brief
 * @version 0.1
 * @date 2022-10-26
 *
 * Copyright:
 * © 2018 北京灵汐科技有限公司 版权所有。
 * 注意：以下内容均为北京灵汐科技有限公司原创，未经本公司允许，不得转载，否则将视为侵权；对于不遵守此声明或者其他违法使用以下内容者，本公司依法保留追究权。
 * © 2018 Lynxi Technologies Co., Ltd. All rights reserved.
 * NOTICE: All information contained here is, and remains the property of Lynxi.
 * This file can not be copied or distributed without the permission of Lynxi
 * Technologies Co., Ltd.
 *
 */

#pragma once

#include <lyn_api.h>
#include <iostream>
#include "ipeParam.h"
#include "util.hpp"

enum IPEType { Crop, Resize, Pad, C2C };

struct IpeInfo {
  int32_t cropX;
  int32_t cropY;
  int32_t cropWidth;
  int32_t cropHeight;

  // 图片resize参数
  int32_t resizeWidth;
  int32_t resizeHeight;

  // 图片填充参数
  int32_t padTop;
  int32_t padRight;
  int32_t padBottom;
  int32_t padLeft;

  lynPixelFormat_t c2cFormat;
};

class IpeParamModel : IpeParamBase {
 public:
  IpeParamModel(int iModelWidth, int iModelHeight)
      : IpeParamBase(iModelWidth, iModelHeight) {}
  ~IpeParamModel() {}

  /**
   * @brief  IPE 处理
   *
   * @param  stream IPE 操作插入的流
   * @param  inputData 待处理的数据
   * @param  outputData IPE 处理之后的数据
   */
  virtual void CalcParam(lynStream_t stream, void *inputData,
                         void *outputData) {
    // 结构体reset
    CHECK_ERR(lynIpeResetPicDesc(m_oPicDescIn));
    CHECK_ERR(lynIpeResetPicDesc(m_oPicDescOut));
    CHECK_ERR(lynIpeResetConfigDesc(m_oConfigDesc));
    CHECK_ERR(lynIpeSetInputPicDesc(m_oPicDescIn, inputData, m_iImgWidth,
                                    m_iImgHeight, m_format));

    // 设置操作
    for (auto operation : ipeProcess) {
      switch (operation) {
        case Crop:
          CHECK_ERR(lynIpeSetCropConfig(
              m_oConfigDesc, processInfo.cropX, processInfo.cropY,
              processInfo.cropWidth, processInfo.cropHeight));
          break;
        case Resize:
          CHECK_ERR(lynIpeSetResizeConfig(m_oConfigDesc,
                                          processInfo.resizeWidth,
                                          processInfo.resizeHeight));
          ;
          break;
        case Pad:
          CHECK_ERR(lynIpeSetPadConfig(
              m_oConfigDesc, processInfo.padTop, processInfo.padRight,
              processInfo.padBottom, processInfo.padLeft, 114, 114, 114));
          break;
        case C2C:
          CHECK_ERR(
              lynIpeSetC2CConfig(m_oConfigDesc, processInfo.c2cFormat, 0));
          break;
        default:
          break;
      }
    }

    CHECK_ERR(lynIpeSetOutputPicData(m_oPicDescOut, outputData));
    CHECK_ERR(
        lynIpeCalOutputPicDesc(m_oPicDescOut, m_oPicDescIn, m_oConfigDesc, 0));
    CHECK_ERR(
        lynIpeProcessAsync(stream, m_oPicDescIn, m_oPicDescOut, m_oConfigDesc));
  }

  virtual void SetImgInfo(int32_t width, int32_t height,
                          lynPixelFormat_t format) {
    if (width > height) {
      processInfo.resizeWidth = m_iModelWidth;
      // & ~1 是为了取偶数，yuv格式不能用奇数去进行ipe
      processInfo.resizeHeight = (height * m_iModelWidth / width) & ~1;
      processInfo.padRight = processInfo.padLeft = 0;
      processInfo.padTop = processInfo.padBottom =
          (m_iModelHeight - processInfo.resizeHeight) / 2;  //
    } else {
      processInfo.resizeWidth = (width * m_iModelWidth / height) & ~1;
      processInfo.resizeHeight = m_iModelHeight;
      processInfo.padRight = processInfo.padLeft =
          (m_iModelWidth - processInfo.resizeWidth) / 2;
      processInfo.padTop = processInfo.padBottom = 0;
    }
    processInfo.c2cFormat = LYN_PIX_FMT_RGB24;
    ipeProcess = {Resize, Pad, C2C};

    IpeParamBase::SetImgInfo(width, height, format);
  }

  void MergeImage(lynStream_t stream, void *outputData,
                  std::vector<ImageMergeInfo> &inputDatas) {
    CHECK_ERR(lynIpeResetPicDesc(m_oPicDescOut));
    CHECK_ERR(lynIpeResetConfigDesc(m_oConfigDesc));
    CHECK_ERR(lynIpeSetOutputPicDesc(m_oPicDescOut, outputData, m_iImgWidth,
                                     m_iImgHeight, m_format));
    for (auto inputData : inputDatas) {
      if (inputData.frame == nullptr) {
        continue;
      }
      CHECK_ERR(lynIpeResetPicDesc(m_oPicDescIn));
      CHECK_ERR(lynIpeSetInputPicDesc(m_oPicDescIn, inputData.frame->data,
                                      inputData.videoInfo.width,
                                      inputData.videoInfo.height, m_format));
      CHECK_ERR(lynIpeSetCropConfig(m_oConfigDesc, 0, 0,
                                    inputData.videoInfo.width,
                                    inputData.videoInfo.height));
      CHECK_ERR(lynIpeSetOutputRect(m_oConfigDesc, inputData.x, inputData.y,
                                    inputData.width, inputData.heigh, false));
      CHECK_ERR(lynIpeProcessAsync(stream, m_oPicDescIn, m_oPicDescOut,
                                   m_oConfigDesc));
    }
  }

 private:
  IpeInfo processInfo;
  std::vector<IPEType> ipeProcess;
};
